#ifndef _ODN_FILE_READER_H
#define _ODN_FILE_READER_H

//Standard library headers
#include <cstdio>
#include <string>
#include <iostream>
#include <cassert>

using std::cout;
using std::endl;
using std::string;

namespace ouden
{
	namespace file
	{
		
		//Base class for loadable and saveable objects
		//They are derived with virtual inheritence, which means only one of these (ie the file variable) exists if an object inherits both LoadableObject and SaveableObject through multiple inheritance  
		class ODN_DataFileAccessingObject
		{
			
			public:
				
				//File pointer 
				FILE* file;
				
			protected:
				
				//Specific typedefs for loading data from files 
				typedef char 				BYTE;
				typedef long 				LONG;
				typedef unsigned short		WORD;
				typedef unsigned long 		DWORD;
				typedef unsigned long long 	QWORD;
				typedef float				SINGLE;
				typedef double				DOUBLE;
				typedef char*				STRING;
				
				//Section header structure 
				struct sSectionHeader {
					WORD SectionID;
					DWORD SectionLength;
				};
				
			private:
				
				
			
		};
		
		//Abstract class which allows class data to be loaded from a file 
		//Used as a base class for objects whose data is to be loaded from a file 
		class ODN_LoadableObject : virtual private ODN_DataFileAccessingObject
		{
			
		public:
			
			//Load all data from the specified file 
			bool loadFromDataFile(char* Filename);
			
		protected:
			
			//Wrapper for reading data from the file into a variable 
			void readData(void* Data) 		{ assert(Data); assert(file); fread(Data, sizeof(Data), 1, file); }
			
			//Wrapper for reading data from the file into an array 
			void readDataArray(void* Data, int Count) 		{ assert(Data); assert(file); fread(Data, sizeof(Data), Count, file); }
			
			//Called to load the header of the data file 
			//virtual void readDataHeader() = 0;
			
			//TODO: Think about having array of recognised sections with addRecognisedSection() function and remove need for virtual processDataSection function 
			
			//Called for each section found in data file 
			//Switches the SectionID and loads any that are recognised 
			//Does nothing if SectionID is not recognised 
			virtual void loadDataSection(WORD SectionID) = 0;
			
			//Grab the sSectionHeader structure and make it protected in here so that derived classes can use it 
			//TODO: This is a bit dodgy 
			using ODN_DataFileAccessingObject::sSectionHeader;
			
		private:
			
			
		};
		
		//Base class for objects requiring the ability to save their data
		//TODO: Look at it closely and see if can remove dodgyness 
		class ODN_SaveableObject : virtual private ODN_DataFileAccessingObject 
		{
			
		public:
			
			//Opens a file in preparation for writing 
			bool openFileToSaveTo(char* Filename)		{ assert(Filename); file = fopen(Filename, "wb"); if (!file) {cout << "File " << Filename << " could not be opened for saving" << endl;	return false; } }
			
			//Begins a section in the file into which data can be written 
			void beginSection(WORD SectionID);
			
			//Wrapper for writing data to a section in a file 
			void writeData(void* Data)		{ assert(Data); assert(file); fwrite(Data, sizeof(Data), 1, file); }
			
			//Ends the current section in the file 
			void endSection();
			
		private:
			
			DWORD cursectionoffset, cursectionlength;
			
			bool insidesection; 
			
		};
		
		/*
		class ODN_File
		{
			
		public:
			
			ODN_File()		{}
			~ODN_File()		{ delete [] sections; }
			
			bool loadFile(char* Filename)
			{
				
				//Open file for reading binary data 
				FILE* File = fopen(Filename, "rb");
				
				//Check that the file loaded ok 
				if (!File) {
					
					cout << "File " << Filename << " not found" << endl;
					return false;
					
				}
				
				//Read the number of sections 
				fread(&sectioncount, sizeof(sectioncount), 1, File);
				
				//Create a new array for the section headers 
				sections = new SectionHeader[sectioncount];
				
				//Read the section headers 
				fread(sections, sizeof(SectionHeader), sectioncount, File);
				
			}
			
			//TODO: Work out this
			//bool seekSection(
			
		private:
			
			//Header for a section of a file 
			struct SectionHeader {
				char TagMarker;
				long Offset;
			};
			
			//Number of sections in the file 
			char sectioncount;
			
			//Array of file sections 
			SectionHeader*		sections; 
			//vector<SectionHeader>		sections;
			
		};
		
		//Standard Ouden file structure is 
		//0		SectionCount
		//1		SectionHeader list 
		//...
		//i		Section TagMarker
		//i+1	Section Data list
		//...
		//j		Section TagMarker
		//j+1	Section Data list
		//...
		
		
		
		//Reads a tagged section of data usually from the returned data of loadFile()
		string seekSection(FILE* File, char TagMarker)
		{
			
			//Sections are tagged with 1 byte TagMarker followed by 4 byte section length value 
			//TODO: See if can make code less dodgy 
			//TODO: Test 
			
			//Find the TagMarker in the data 
			//unsigned int i = Data.find(TagMarker, 0);
			
			//If the TagMarker wasn't found 
			//if (i==string::npos)
			//	return 0;
				
			//Get the section length value 
			//unsigned int SectionLength = atoi(Data.substr(i + 1, 4).c_str());
			
			//Return the section data 
			//return Data.substr(i + 1 + 4, SectionLength);
			
		}
		
		//Loads a file and returns a file pointer to it 
		FILE* openFile(char* Filename)
		{
			
			//Open file for reading binary data 
			FILE* File = fopen(Filename, "rb");
			
			//Check that the file loaded ok 
			if (!File) {
				
				cout << "File " << Filename << " not found" << endl;
				return false;
				
			}
			
			//Return the file pointer 
			return File;
			
		}
		
		string ReadTag(string Data, string Name, int Start = -1);
		string GetLine(FILE* File);
		string ReadFile(string Name);
		*/
	} //namespace file
} //namespace ouden

#endif //_ODN_FILE_READER_H 
